using Microsoft.Extensions.Logging;
using SumerCoreDevOps.Shared.Enums;
using SumerCoreDevOps.Shared.Models;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.RegularExpressions;

namespace SumerCoreDevOps.ExecuteNodeApi.Services;

/// <summary>
/// 环境检测服务 - 检测系统中已安装的构建环境
/// </summary>
public class EnvironmentDetector
{
    private readonly ILogger<EnvironmentDetector> _logger;
    private readonly Dictionary<string, EnvironmentInfo> _cachedEnvironments = [];

    public EnvironmentDetector(ILogger<EnvironmentDetector> logger)
    {
        _logger = logger;
    }

    /// <summary>
    /// 检测所有已安装的环境
    /// </summary>
    public async Task<List<EnvironmentInfo>> DetectAllEnvironmentsAsync()
    {
        _logger.LogInformation("开始检测系统环境...");

        var environments = new List<EnvironmentInfo>();

        // 并行检测所有环境
        var tasks = new[]
        {
            DetectDotNetAsync(),
            DetectJavaAsync(),
            DetectMavenAsync(),
            DetectGradleAsync(),
            DetectNodeAsync(),
            DetectNpmAsync(),
            DetectYarnAsync(),
            DetectPnpmAsync(),
            DetectPythonAsync(),
            DetectRustAsync(),
            DetectGoAsync(),
            DetectDockerAsync(),
            DetectGitAsync()
        };

        var results = await Task.WhenAll(tasks);

        foreach (var env in results.Where(e => e != null && e.IsInstalled))
        {
            environments.Add(env!);
            _cachedEnvironments[env!.Name] = env;
        }

        _logger.LogInformation("环境检测完成，检测到 {Count} 个环境", environments.Count);

        return environments;
    }

    /// <summary>
    /// 获取支持的环境列表（用于节点注册）
    /// </summary>
    public async Task<List<string>> GetSupportedEnvironmentsAsync()
    {
        var environments = await DetectAllEnvironmentsAsync();
        return environments
            .Select(e => $"{e.Name}:{e.Version}")
            .ToList();
    }

    /// <summary>
    /// 检测特定环境
    /// </summary>
    public async Task<EnvironmentInfo?> DetectEnvironmentAsync(string name)
    {
        // 检查缓存
        if (_cachedEnvironments.TryGetValue(name.ToLowerInvariant(), out var cached))
        {
            return cached;
        }

        return name.ToLowerInvariant() switch
        {
            "dotnet" or ".net" => await DetectDotNetAsync(),
            "java" => await DetectJavaAsync(),
            "maven" or "mvn" => await DetectMavenAsync(),
            "gradle" => await DetectGradleAsync(),
            "node" or "nodejs" => await DetectNodeAsync(),
            "npm" => await DetectNpmAsync(),
            "yarn" => await DetectYarnAsync(),
            "pnpm" => await DetectPnpmAsync(),
            "python" => await DetectPythonAsync(),
            "rust" or "cargo" => await DetectRustAsync(),
            "go" or "golang" => await DetectGoAsync(),
            "docker" => await DetectDockerAsync(),
            "git" => await DetectGitAsync(),
            _ => null
        };
    }

    /// <summary>
    /// 检查环境是否满足需求
    /// </summary>
    public async Task<(bool IsSatisfied, string? Message)> CheckRequirementAsync(EnvironmentRequirement requirement)
    {
        var env = await DetectEnvironmentAsync(requirement.Name);

        if (env == null || !env.IsInstalled)
        {
            return (false, $"{requirement.Name} 未安装");
        }

        // 如果指定了最低版本，检查版本
        if (!string.IsNullOrEmpty(requirement.MinVersion))
        {
            if (!IsVersionSatisfied(env.Version, requirement.MinVersion))
            {
                return (false, $"{requirement.Name} 版本过低：当前 {env.Version}，需要 {requirement.MinVersion} 或更高");
            }
        }

        return (true, null);
    }

    #region 环境检测方法

    private async Task<EnvironmentInfo> DetectDotNetAsync()
    {
        var result = await ExecuteCommandAsync("dotnet", "--version");
        return new EnvironmentInfo
        {
            Name = "dotnet",
            Version = result.Success ? result.Output.Trim() : "未安装",
            IsInstalled = result.Success,
            Metadata = new Dictionary<string, string>
            {
                ["FullOutput"] = result.Output
            }
        };
    }

    private async Task<EnvironmentInfo> DetectJavaAsync()
    {
        var result = await ExecuteCommandAsync("java", "-version");
        var version = ParseJavaVersion(result.Output);

        return new EnvironmentInfo
        {
            Name = "java",
            Version = version ?? "未安装",
            IsInstalled = result.Success,
            Metadata = new Dictionary<string, string>
            {
                ["FullOutput"] = result.Output
            }
        };
    }

    private async Task<EnvironmentInfo> DetectMavenAsync()
    {
        var result = await ExecuteCommandAsync("mvn", "--version");
        var version = ParseMavenVersion(result.Output);

        return new EnvironmentInfo
        {
            Name = "maven",
            Version = version ?? "未安装",
            IsInstalled = result.Success
        };
    }

    private async Task<EnvironmentInfo> DetectGradleAsync()
    {
        var result = await ExecuteCommandAsync("gradle", "--version");
        var version = ParseGradleVersion(result.Output);

        return new EnvironmentInfo
        {
            Name = "gradle",
            Version = version ?? "未安装",
            IsInstalled = result.Success
        };
    }

    private async Task<EnvironmentInfo> DetectNodeAsync()
    {
        var result = await ExecuteCommandAsync("node", "--version");
        var version = result.Output.Trim().TrimStart('v');

        return new EnvironmentInfo
        {
            Name = "node",
            Version = result.Success ? version : "未安装",
            IsInstalled = result.Success
        };
    }

    private async Task<EnvironmentInfo> DetectNpmAsync()
    {
        var result = await ExecuteCommandAsync("npm", "--version");
        return new EnvironmentInfo
        {
            Name = "npm",
            Version = result.Success ? result.Output.Trim() : "未安装",
            IsInstalled = result.Success
        };
    }

    private async Task<EnvironmentInfo> DetectYarnAsync()
    {
        var result = await ExecuteCommandAsync("yarn", "--version");
        return new EnvironmentInfo
        {
            Name = "yarn",
            Version = result.Success ? result.Output.Trim() : "未安装",
            IsInstalled = result.Success
        };
    }

    private async Task<EnvironmentInfo> DetectPnpmAsync()
    {
        var result = await ExecuteCommandAsync("pnpm", "--version");
        return new EnvironmentInfo
        {
            Name = "pnpm",
            Version = result.Success ? result.Output.Trim() : "未安装",
            IsInstalled = result.Success
        };
    }

    private async Task<EnvironmentInfo> DetectPythonAsync()
    {
        // 尝试 python3 和 python
        var result = await ExecuteCommandAsync("python3", "--version");
        if (!result.Success)
        {
            result = await ExecuteCommandAsync("python", "--version");
        }

        var version = result.Output.Replace("Python", "").Trim();

        return new EnvironmentInfo
        {
            Name = "python",
            Version = result.Success ? version : "未安装",
            IsInstalled = result.Success
        };
    }

    private async Task<EnvironmentInfo> DetectRustAsync()
    {
        var result = await ExecuteCommandAsync("rustc", "--version");
        var version = result.Output.Replace("rustc", "").Split(' ')[0].Trim();

        return new EnvironmentInfo
        {
            Name = "rust",
            Version = result.Success ? version : "未安装",
            IsInstalled = result.Success
        };
    }

    private async Task<EnvironmentInfo> DetectGoAsync()
    {
        var result = await ExecuteCommandAsync("go", "version");
        var version = ParseGoVersion(result.Output);

        return new EnvironmentInfo
        {
            Name = "go",
            Version = version ?? "未安装",
            IsInstalled = result.Success
        };
    }

    private async Task<EnvironmentInfo> DetectDockerAsync()
    {
        var result = await ExecuteCommandAsync("docker", "--version");
        var version = ParseDockerVersion(result.Output);

        return new EnvironmentInfo
        {
            Name = "docker",
            Version = version ?? "未安装",
            IsInstalled = result.Success
        };
    }

    private async Task<EnvironmentInfo> DetectGitAsync()
    {
        var result = await ExecuteCommandAsync("git", "--version");
        var version = result.Output.Replace("git version", "").Trim();

        return new EnvironmentInfo
        {
            Name = "git",
            Version = result.Success ? version : "未安装",
            IsInstalled = result.Success
        };
    }

    #endregion

    #region 版本解析

    private string? ParseJavaVersion(string output)
    {
        // 输出示例：java version "17.0.1" 或 openjdk version "17.0.1"
        var match = Regex.Match(output, @"version ""(.+?)""");
        return match.Success ? match.Groups[1].Value : null;
    }

    private string? ParseMavenVersion(string output)
    {
        // 输出示例：Apache Maven 3.8.6
        var match = Regex.Match(output, @"Apache Maven (\d+\.\d+\.\d+)");
        return match.Success ? match.Groups[1].Value : null;
    }

    private string? ParseGradleVersion(string output)
    {
        // 输出示例：Gradle 8.0
        var match = Regex.Match(output, @"Gradle (\d+\.\d+)");
        return match.Success ? match.Groups[1].Value : null;
    }

    private string? ParseGoVersion(string output)
    {
        // 输出示例：go version go1.21.0 linux/amd64
        var match = Regex.Match(output, @"go version go(\d+\.\d+\.\d+)");
        return match.Success ? match.Groups[1].Value : null;
    }

    private string? ParseDockerVersion(string output)
    {
        // 输出示例：Docker version 24.0.6, build ed223bc
        var match = Regex.Match(output, @"Docker version (\d+\.\d+\.\d+)");
        return match.Success ? match.Groups[1].Value : null;
    }

    #endregion

    #region 版本比较

    private bool IsVersionSatisfied(string current, string minimum)
    {
        try
        {
            var currentVersion = ParseVersion(current);
            var minimumVersion = ParseVersion(minimum);

            return currentVersion >= minimumVersion;
        }
        catch
        {
            _logger.LogWarning("版本比较失败: {Current} vs {Minimum}", current, minimum);
            return true; // 如果无法比较，则假设满足要求
        }
    }

    private Version ParseVersion(string version)
    {
        // 移除前缀和后缀（如 v1.0.0 或 1.0.0-beta）
        var cleaned = Regex.Replace(version, @"[^\d\.].*$", "");
        cleaned = cleaned.TrimStart('v');

        return Version.Parse(cleaned);
    }

    #endregion

    #region 辅助方法

    private async Task<(bool Success, string Output)> ExecuteCommandAsync(string command, string arguments, int timeoutMs = 5000)
    {
        try
        {
            var startInfo = new ProcessStartInfo
            {
                FileName = command,
                Arguments = arguments,
                RedirectStandardOutput = true,
                RedirectStandardError = true,
                UseShellExecute = false,
                CreateNoWindow = true
            };

            using var process = new Process { StartInfo = startInfo };
            var output = new StringBuilder();
            var error = new StringBuilder();

            process.OutputDataReceived += (s, e) =>
            {
                if (!string.IsNullOrEmpty(e.Data))
                    output.AppendLine(e.Data);
            };

            process.ErrorDataReceived += (s, e) =>
            {
                if (!string.IsNullOrEmpty(e.Data))
                    error.AppendLine(e.Data);
            };

            process.Start();
            process.BeginOutputReadLine();
            process.BeginErrorReadLine();

            using var cts = new CancellationTokenSource(timeoutMs);
            await process.WaitForExitAsync(cts.Token);

            var result = output.Length > 0 ? output.ToString() : error.ToString();
            return (process.ExitCode == 0, result);
        }
        catch (Exception ex)
        {
            _logger.LogDebug("命令执行失败: {Command} {Arguments} - {Error}", command, arguments, ex.Message);
            return (false, string.Empty);
        }
    }

    #endregion
}
